home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
bbs_util
/
bsrc_260.zip
/
SRC.ZIP
/
XMREC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-20
|
31KB
|
1,323 lines
/*--------------------------------------------------------------------------*/
/* */
/* */
/* ------------ Bit-Bucket Software, Co. */
/* \ 10001101 / Writers and Distributors of */
/* \ 011110 / Freely Available<tm> Software. */
/* \ 1011 / */
/* ------ */
/* */
/* (C) Copyright 1987-96, Bit Bucket Software Co. */
/* */
/* This module was written by Bob Hartman */
/* */
/* BinkleyTerm Xmodem Receiver State Machine */
/* */
/* */
/* For complete details of the licensing restrictions, please refer */
/* to the License agreement, which is published in its entirety in */
/* the MAKEFILE and BT.C, and also contained in the file LICENSE.260. */
/* */
/* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */
/* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */
/* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */
/* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */
/* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */
/* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */
/* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */
/* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */
/* */
/* */
/* You can contact Bit Bucket Software Co. at any one of the following */
/* addresses: */
/* */
/* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */
/* P.O. Box 460398 AlterNet 7:42/1491 */
/* Aurora, CO 80046 BBS-Net 86:2030/1 */
/* Internet f491.n343.z1.fidonet.org */
/* */
/* Please feel free to contact us at any time to share your comments about */
/* our software and/or licensing policies. */
/* */
/*--------------------------------------------------------------------------*/
/* Include this file before any other includes or defines! */
#include "includes.h"
void Find_Char (int);
int Header_in_data (unsigned char *);
void Send_ACK (XMARGSP);
void Send_NAK (XMARGSP);
long Open_Xmodem_File (XMARGSP);
int XRInit (XMARGSP);
int XREnd (XMARGSP);
int XRRecInit (XMARGSP);
int XRBrecInit (XMARGSP);
int XRRecStart (XMARGSP);
int XRWaitFirst (XMARGSP);
int XRWaitBlock (XMARGSP);
int XRRestart (XMARGSP);
int XRSetOvrdr (XMARGSP);
typedef struct
{
char *state_name;
int (*state_func) (XMARGSP);
} XSTATES, *XSTATEP;
XSTATES Xmodem_Receiver[] =
{
{"XRInit", XRInit},
{"XREnd", XREnd},
{"XR0", XRRecInit},
{"XR0B", XRBrecInit},
{"XR1", XRRecStart},
{"XR2", XRWaitFirst},
{"XR3", XRWaitBlock},
{"XR4", XRRestart},
{"XR5", XRSetOvrdr}
};
long
Open_Xmodem_File (XMARGSP args)
{
char *s1, *s2;
if (args->file_pointer == NULL)
{
args->temp_name = calloc (1, 80);
if (args->path != NULL)
(void) strcpy (args->temp_name, args->path);
s1 = &(args->temp_name[strlen (args->temp_name)]);
(void) strcpy (s1, "BTXXXXXX");
s2 = mktemp (args->temp_name);
if ((s2 == NULL) || ((args->file_pointer = fopen (s2, write_binary)) == NULL))
{
status_line (MSG_TXT (M_TEMP_NOT_OPEN), s2);
return (-1L);
}
}
throughput (0, 0L);
return (0L);
}
long
Set_Up_Restart (XMARGSP args)
{
char foo[100];
char foo1[50];
struct stat st;
args->sub_results = 0;
/* Look for file in directory */
if (args->path != NULL)
(void) strcpy (foo, args->path);
if ((args->received_name != NULL) &&
(strlen (args->received_name) > 0) &&
args->options.Resync)
{
(void) strcat (foo, args->received_name);
if (stat (foo, &st) == 0)
{
if ((st.st_size == args->filelen) && (st.st_atime == (time_t) (args->save_filetime.oneword.timedate)))
{
if ((args->file_pointer = fopen (foo, "rb+")) != NULL)
{
throughput (0, 0L);
(void) fseek (args->file_pointer, 0L, SEEK_END);
args->sub_results = DID_RESYNC;
args->temp_name = calloc (1, 80);
(void) strcpy (args->temp_name, foo);
args->prev_bytes = args->filelen;
status_line (MSG_TXT (M_ALREADY_HAVE), foo);
status_line (MSG_TXT (M_SYNCHRONIZING_EOF));
return (args->total_blocks + 1L);
}
}
}
/* Look for file in .Z file */
if (dexists (Abortlog_name))
{
(void) sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
if (check_failed (Abortlog_name, args->received_name, Resume_info, foo1))
{
foo[0] = '\0';
/* Here it looks like it was a failed WaZOO session */
if (args->path != NULL)
(void) strcpy (foo, args->path);
(void) strcat (foo, foo1);
if ((args->file_pointer = fopen (foo, "rb+")) != NULL)
{
(void) stat (foo, &st);
throughput (0, 0L);
args->temp_name = calloc (1, 80);
(void) strcpy (args->temp_name, foo);
args->prev_bytes = (st.st_size / 128L) * 128L;
(void) fseek (args->file_pointer, args->prev_bytes, SEEK_SET);
status_line (MSG_TXT (M_SYNCHRONIZING_OFFSET), args->prev_bytes);
return (args->prev_bytes / 128L + 1L);
}
}
}
}
return (Open_Xmodem_File (args));
}
void
Finish_Xmodem_Receive (XMARGSP args)
{
struct stat st;
char new_name[80];
struct utimbuf times;
int i, j, k;
/* Set the file's time and date stamp */
if ((args->save_header == SOH) || (args->save_header == SYN))
{
(void) fclose (args->file_pointer);
times.modtime = times.UT_ACTIME = (time_t) args->save_filetime.oneword.timedate;
(void) utime (args->temp_name, (UTIMBUF *) & times);
}
else
{
(void) strcpy (args->received_name, "");
if (args->file_pointer)
(void) fclose (args->file_pointer);
}
if (args->result == SUCCESS)
{
long lFileTime;
long lFileSize;
/* Get the file information */
(void) stat (args->temp_name, &st);
lFileSize = st.st_size - args->prev_bytes;
lFileTime = throughput (1, (unsigned long)lFileSize);
if (args->sub_results & DID_RESYNC)
{
status_line ("%s: %s", MSG_TXT (M_FILE_RECEIVED), args->temp_name);
update_files (0, args->temp_name, lFileSize, lFileTime, 0);
}
else
{
new_name[0] = '\0';
if (args->path != NULL)
(void) strcpy (new_name, args->path);
if ((args->filename == NULL) || (strlen (args->filename) == 0))
{
if (strlen (args->received_name) > 0)
(void) strcat (new_name, args->received_name);
else
(void) strcat (new_name, "BAD_FILE.000");
}
else
{
(void) strcat (new_name, args->filename);
}
i = (int) strlen (args->temp_name) - 1;
j = (int) strlen (new_name) - 1;
if (args->temp_name[i] == '.')
args->temp_name[i] = '\0';
if (new_name[j] == '.')
{
new_name[j] = '\0';
--j;
}
i = 0;
k = is_arcmail (new_name, j);
status_line ("%s: %s", MSG_TXT (M_FILE_RECEIVED), new_name);
update_files (0, new_name, lFileSize, lFileTime, 0);
if ((!overwrite) || k)
{
while (rename (args->temp_name, new_name))
{
if (isdigit (new_name[j]))
new_name[j]++;
else
new_name[j] = '0';
if (!isdigit (new_name[j]))
{
return;
}
i = 1;
}
CLEAR_IOERR ();
}
else
{
(void) unlink (new_name);
while (rename (args->temp_name, new_name))
{
if (!i)
{
status_line (MSG_TXT (M_ORIGINAL_NAME_BAD), new_name);
}
if (isdigit (new_name[j]))
new_name[j]++;
else
new_name[j] = '0';
if (!isdigit (new_name[j]))
{
return;
}
i = 1;
}
CLEAR_IOERR ();
}
if (i)
{
if (locate_y && !(fullscreen && un_attended))
gotoxy (2, locate_y - 1);
status_line (MSG_TXT (M_RENAME_MSG), new_name);
}
}
remove_abort (Abortlog_name, args->received_name);
}
else
{
if ((args->received_name != NULL) && (strlen (args->received_name) > 0) && (args->save_header != 0))
{
(void) sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
add_abort (Abortlog_name, args->received_name, args->temp_name, args->path, Resume_info);
}
else
{
/* File aborted, so remove all traces of it */
if (args->temp_name != NULL)
(void) unlink (args->temp_name);
}
}
if (args->temp_name != NULL)
{
free (args->temp_name);
}
}
void
Get_Telink_Info (XMARGSP args)
{
char *p1;
char junkbuff[100];
TLDATAP t;
unsigned int i, j;
struct tm tmstruc;
time_t curr_time;
/* Figure out how many blocks we will get */
t = (TLDATAP) & (args->header);
args->total_blocks = (t->filelength + 127) / 128;
t->nullbyte = '\0';
p1 = strchr (t->filename, ' ');
if (p1 != NULL)
*p1 = '\0';
/* Rename .REQ files */
i = strlen (t->filename) - 4;
if ((i > 0) && (stricmp (&(t->filename)[i], ".REQ") == 0))
{
(t->filename)[i] = '\0';
status_line (MSG_TXT(M_REC_REQ_AS), t->filename, t->filename, TaskNumber);
sprintf (&(t->filename)[i],".R%02x", TaskNumber);
}
(void) strcpy (args->received_name, t->filename);
args->save_header = args->header;
if (args->save_header == SYN)
{
i = t->filetime.twowords.time;
j = t->filetime.twowords.date;
curr_time = time (NULL);
tmstruc = *localtime (&curr_time); /* Structure assignment */
tmstruc.tm_year = (j >> 9) + 80;
tmstruc.tm_mon = ((j >> 5) & 0x0f) - 1;
tmstruc.tm_mday = j & 0x1f;
tmstruc.tm_hour = i >> 11;
tmstruc.tm_min = (i >> 5) & 0x3f;
tmstruc.tm_sec = i & 0x1f;
args->save_filetime.oneword.timedate = mktime (&tmstruc);
}
else
{
#ifdef ANSI_TIME_T
args->save_filetime.oneword.timedate = t->filetime.oneword.timedate + ANSI_TIME_T_DELTA;
#else
args->save_filetime.oneword.timedate = t->filetime.oneword.timedate;
#endif
}
args->filelen = t->filelength;
(void) sprintf (junkbuff, MSG_TXT (M_RECEIVE_MSG),
args->total_blocks, t->filename, t->sendingprog, t->filelength);
(void) strncpy (args->sending_program, t->sendingprog, 15);
if (un_attended && fullscreen)
{
clear_filetransfer ();
sb_move (filewin, 1, 2);
sb_puts (filewin, junkbuff);
elapse_time ();
sb_show ();
}
else
{
status_line ("+%s", junkbuff);
(void) printf ("\n");
locate_y = wherey ();
locate_x = wherex ();
}
}
int
Read_Block (XMARGSP args)
{
unsigned char *p; /* Pointers to XMODEM data */
int i; /* Counter */
int j; /* Counter start */
unsigned char c; /* character being processed */
int in_char;
char junkbuff[128];
long head_timer;
struct _pkthdr *packet; /* FTS-0001 packet type */
struct _pkthdr45 *pkt0045; /* FSC-0045 packet type */
struct _pkthdr39 *pkt0039; /* FSC-0039 packet type */
unsigned int cwtest; /* Used to verify FSC-0039 type */
if (got_ESC ())
{
status_line (MSG_TXT (M_KBD_MSG));
return (KBD_ERR);
}
/* Set up to point into the XMODEM data structure */
p = (unsigned char *) &(args->header);
/* Get the first character that is waiting */
*p = (unsigned char) TIMED_READ (8);
head_timer = timerset (6000);
j = 1;
while (!timeup (head_timer))
{
/* Now key off of the header character */
switch (*p)
{
case EOT: /* End of file */
/* Is this a valid EOT */
if (args->total_blocks <= args->WriteBLK)
{
return (EOT_BLOCK);
}
else
{
status_line (MSG_TXT (M_UNEXPECTED_EOF), args->total_blocks);
return (BAD_BLOCK);
}
case SYN: /* Telink block */
/* For Telink, read all of the data except the checksum */
for (i = 1; i < sizeof (TLDATA) - 2; i++)
{
/* If we go more than 5 second, then we have a short block */
if ((in_char = TIMED_READ (5)) < 0)
{
return (BAD_BLOCK);
}
*(++p) = (unsigned char) (in_char & 0xff);
}
/* if the block number or its complement are wrong, return error */
if ((args->block_num != 0) || (args->block_num_comp != 0xff))
{
return (BAD_BLOCK);
}
/* Now calculate the checksum - Telink block always checksum mode */
Data_Check ((XMDATAP) & (args->header), CHECKSUM);
/* See if we can receive the checksum byte */
if ((in_char = TIMED_READ (10)) < 0)
{
Xmodem_Error (MSG_TXT (M_TIMEOUT), 0L);
return (BAD_BLOCK);
}
/* Was it right */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[0])
{
Xmodem_Error (MSG_TXT (M_CHECKSUM), 0L);
return (BAD_BLOCK);
}
/* Everything looks good, it must be a legal TELINK block */
Get_Telink_Info (args);
return (TELINK_BLOCK);
case SOH: /* Normal data block */
args->datalen = 128;
/* Read in all of the data for an XMODEM block except the checksum */
p += (j - 1);
for (i = j; i < sizeof (XMDATA) - 2; i++)
{
/* If we go more than 5 seconds, then it is a short block */
if ((in_char = TIMED_READ (5)) < 0)
{
return (BAD_BLOCK);
}
*(++p) = (unsigned char) (in_char & 0xff);
}
/* The block number is 0 to 255 inclusive */
c = (unsigned char) (args->blocknum & 0xff);
/* Properly calculate the CRC or checksum */
Data_Check ((XMDATAP) & (args->header), args->options.do_CRC ? CRC : CHECKSUM);
/* Can we get the checksum byte */
if ((in_char = TIMED_READ (10)) < 0)
{
Xmodem_Error (MSG_TXT (M_TIMEOUT), args->WriteBLK);
return (BAD_BLOCK);
}
/* Is it the right value */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[0])
{
status_line (">Xmodem Receive: Bad %s", (args->options.do_CRC) ? "CRC" : "checksum");
Xmodem_Error (MSG_TXT (M_CRC_MSG), args->WriteBLK);
if (args->options.do_CRC)
(void) TIMED_READ (5);
return (BAD_BLOCK);
}
/* If we are in CRC mode, do the second byte */
if (args->options.do_CRC)
{
/* Can we get the character */
if ((in_char = TIMED_READ (10)) < 0)
{
status_line (">Xmodem Receive: Timeout waiting for CRC byte 2");
Xmodem_Error (MSG_TXT (M_TIMEOUT), args->WriteBLK);
return (BAD_BLOCK);
}
/* Is it right */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[1])
{
Xmodem_Error (MSG_TXT (M_CRC_MSG), args->WriteBLK);
return (BAD_BLOCK);
}
}
/* Do we have a valid data block */
if (args->block_num_comp != (unsigned char) ((~(args->block_num)) & 0xff))
{
if (!(args->options.SEAlink))
{
Xmodem_Error (MSG_TXT (M_JUNK_BLOCK), args->WriteBLK);
return (BAD_BLOCK);
}
p = (unsigned char *) &(args->header);
j = Header_in_data (p);
if (j)
{
continue;
}
j = 1;
Find_Char (SOH);
*p = (unsigned char) TIMED_READ (0);
}
if ((args->WriteBLK == 1) && (args->header == SOH) && (args->block_num == 0))
{
Get_Telink_Info (args);
return (SEALINK_BLOCK);
}
if (first_block)
{
packet = (struct _pkthdr *) args->data;
pkt0045 = (struct _pkthdr45 *) packet;
pkt0039 = (struct _pkthdr39 *) packet;
if (!remote_capabilities)
{
remote_addr.Net = packet->orig_net;
remote_addr.Node = packet->orig_node;
if (packet->rate == 2)
{
/* This is a FSC-0045 (type 2.2) packet! */
remote_addr.Zone = packet->orig_zone;
remote_addr.Point = (unsigned) pkt0045->orig_point;
strncpy (junkbuff, (char *) (pkt0045->orig_domain), 8);
junkbuff[8] = '\0';
remote_addr.Domain = find_domain (junkbuff);
}
else
{
remote_addr.Domain = NULL;
cwtest = (((pkt0039->CapValid) & 0x7f00) >> 8) +
(((pkt0039->CapValid) & 0x007f) << 8);
if (cwtest == (unsigned int) ((pkt0039->CapWord) & 0x7f7f))
{
/* This is a FSC-0039 packet! */
remote_addr.Zone = pkt0039->orig_zone;
remote_addr.Point = pkt0039->orig_point;
}
else
{
remote_addr.Zone = packet->orig_zone;
remote_addr.Point = 0;
}
}
/*
* Here we have extracted the Zone, Net, Node, Point and Domain from the
* packet -- regardless of type. Now see if we need to map to a fake net
* or to mung the address because it's someone else's point.
*/
if ((remote_addr.Point > 0) &&
(pvtnet >= 0) &&
((remote_addr.Zone == alias[assumed].Zone) || (remote_addr.Zone == 0)) &&
(remote_addr.Net == boss_addr.Net) &&
(remote_addr.Node == boss_addr.Node))
{
remote_addr.Net = pvtnet;
remote_addr.Node = remote_addr.Point;
remote_addr.Point = 0;
}
else if ((pvtnet >= 0) && (remote_addr.Point > 0))
{
remote_addr.Point = 0;
remote_addr.Node = (unsigned short) -1;
}
}
if (who_is_he)
{
if (!remote_addr.Zone && !remote_addr.Net && !remote_addr.Node)
{
LOWER_DTR (); /* Bad trip, cut it off */
timer (2); /* Wait two secs */
return (CARRIER_ERR); /* Get out of here! */
}
if (nodefind (&remote_addr, 1))
{
if (!remote_addr.Zone)
remote_addr.Zone = found_zone;
(void) sprintf (junkbuff, "%s: %s (%s)",
MSG_TXT (M_REMOTE_SYSTEM),
newnodedes.SystemName,
Full_Addr_Str (&remote_addr));
}
else
{
(void) sprintf (junkbuff, "%s: %s (%s)",
MSG_TXT (M_REMOTE_SYSTEM),
MSG_TXT (M_UNKNOWN_MAILER),
Full_Addr_Str (&remote_addr));
}
last_type (2, &remote_addr);
status_line (junkbuff);
}
if (args->sending_program[0] != '\0')
{
status_line ("%s %s", MSG_TXT (M_REMOTE_USES), args->sending_program);
}
else
{
log_product (packet->product, 0, packet->serial);
}
who_is_he = 0;
first_block = 0;
}
if (args->WriteBLK == args->total_blocks)
{
args->datalen = (int) (args->filelen - ((args->WriteBLK - 1) * 128));
}
/* If we got this far, it is a valid data block */
args->recblock = args->block_num;
return (XMODEM_BLOCK);
default: /* Bad block */
if ((args->blocknum <= 1) || (PEEKBYTE () < 0))
return (BAD_BLOCK);
/* Garbage header, return bad */
*p = (unsigned char) TIMED_READ (0);
}
}
return (BAD_BLOCK);
}
int
XRInit (XMARGSP args)
{
char *HoldName;
args->tries = 0;
args->goodfile = 1;
XON_DISABLE ();
HoldName = HoldAreaNameMunge (&called_addr);
(void) sprintf (Abortlog_name, "%s%s.Z\0",
HoldName, Hex_Addr_Str (&remote_addr));
args->sending_program[0] = '\0';
return ((int) args->control);
}
int
XREnd (XMARGSP args)
{
args->result = (int) args->control;
Finish_Xmodem_Receive (args);
return ((int) args->control);
}
int
XRRecInit (XMARGSP args)
{
args->options.SEAlink = 0;
args->options.SLO = 0;
args->options.Resync = 0;
args->options.MacFlow = 0;
args->options.do_CRC = 1;
args->blocknum = 0;
args->WriteBLK = 1;
args->curr_byte = 0L;
args->tries = 0;
return (XR1);
}
int
XRBrecInit (XMARGSP args)
{
args->options.SEAlink = 0;
args->options.SLO = 0;
args->options.Resync = 0;
args->options.MacFlow = 0;
args->options.do_CRC = 1;
args->blocknum = 0;
args->WriteBLK = 1;
args->curr_byte = 0L;
args->tries = 0;
return (XR2);
}
int
XRRecStart (XMARGSP args)
{
Send_NAK (args);
return (XR2);
}
int
XRWaitFirst (XMARGSP args)
{
long XR2Timer;
XR2Timer = timerset (800);
if (args->tries >= 10)
{
args->goodfile = 0;
return (TIME_ERR);
}
if (args->tries == 5)
{
args->options.do_CRC = 0;
++(args->tries);
return (XR1);
}
while (CARRIER)
{
switch (Read_Block (args))
{
case EOT_BLOCK:
args->WriteBLK = 0;
Send_ACK (args);
return (SUCCESS_EOT);
case TELINK_BLOCK:
if (Open_Xmodem_File (args) == -1L)
return (OPEN_ERR);
Send_ACK (args);
args->tries = 0;
return (XR3);
case SEALINK_BLOCK:
args->options.SEAlink = no_sealink ? 0 : 1;
if (args->options.SEAlink && !no_resync)
args->options.Resync = (((SEADATAP) (&(args->header)))->Resync) != 0;
return (XR4);
case XMODEM_BLOCK:
if (args->recblock == 1)
{
if (Open_Xmodem_File (args) == -1L)
return (OPEN_ERR);
(void) fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
++(args->WriteBLK);
args->curr_byte = 128L;
++(args->blocknum);
Send_ACK (args);
args->tries = 0;
return (XR3);
}
/* Fallthrough on wrong block */
case BAD_BLOCK:
++(args->tries);
return (XR1);
case CARRIER_ERR:
case KBD_ERR:
return (CARRIER_ERR);
}
if (timeup (XR2Timer))
{
++(args->tries);
return (XR1);
}
}
return (CARRIER_ERR);
}
int
XRWaitBlock (XMARGSP args)
{
int blocknum_copy;
if (args->tries >= 10)
{
args->goodfile = 0;
return (TIME_ERR);
}
while (CARRIER)
{
switch (Read_Block (args))
{
case EOT_BLOCK:
args->options.SLO = 0;
Send_ACK (args);
return (SUCCESS);
case XMODEM_BLOCK:
blocknum_copy = (int) args->blocknum & 0xff;
if (args->recblock == ((blocknum_copy - 1) & 0xff))
{
--(args->blocknum);
Send_ACK (args);
return (XR3);
}
if (args->recblock == blocknum_copy)
{
(void) fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
++(args->WriteBLK);
args->curr_byte += 128L;
Send_ACK (args);
args->tries = 0;
return (XR3);
}
if (args->recblock < blocknum_copy)
{
args->recblock += 256;
}
if ((args->recblock > blocknum_copy) && (args->recblock <= ((blocknum_copy + 127) & 0xff)))
{
if (args->tries != 0)
{
/* We have sent at least one nak, now only send them
every so often to allow buffers to drain */
if ((args->recblock - blocknum_copy) % 16)
return (XR3);
/* If it is a multiple of 16, then check that it is
higher than 32 */
if ((args->recblock - blocknum_copy) / 16 < 2)
return (XR3);
}
}
/* fallthrough on bad block */
case BAD_BLOCK:
Send_NAK (args);
++(args->tries);
return (XR3);
case CARRIER_ERR:
case KBD_ERR:
return (CARRIER_ERR);
}
}
return (CARRIER_ERR);
}
int
XRRestart (XMARGSP args)
{
long c;
c = Set_Up_Restart (args);
if (c == -1L)
return (OPEN_ERR);
if ((!c) || (!(args->options.Resync)))
{
Send_ACK (args);
args->tries = 0;
}
else
{
args->WriteBLK = c;
args->curr_byte = (c - 1) * 128L;
args->blocknum = (unsigned char) ((args->WriteBLK) & 0xff);
Send_NAK (args);
}
return (XR5);
}
int
XRSetOvrdr (XMARGSP args)
{
if (!no_overdrive)
args->options.SLO = (((SEADATAP) (&(args->header)))->SLO) != 0;
if (args->options.SLO)
show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
return (XR3);
}
int
Xmodem_Receive_File (char *path, char *filename)
{
XMARGS xmfile;
int res;
locate_y = wherey ();
locate_x = wherex ();
(void) memset (&xmfile, 0, sizeof (XMARGS));
xmfile.path = path;
xmfile.filename = filename;
xmfile.total_blocks = -1L;
xmfile.sent_ACK = 0;
res = state_machine ((STATEP) Xmodem_Receiver, &xmfile, XR0);
return (res);
}
int
Batch_Xmodem_Receive_File (char *path, char *filename)
{
XMARGS xmfile;
int res;
locate_y = wherey ();
locate_x = wherex ();
(void) memset (&xmfile, 0, sizeof (XMARGS));
xmfile.path = path;
xmfile.filename = filename;
xmfile.total_blocks = -1L;
xmfile.sent_ACK = 0;
res = state_machine ((STATEP) Xmodem_Receiver, &xmfile, XR0B);
return (res);
}
int SAInit (XMARGSP);
int SAEnd (XMARGSP);
int SAClearLine (XMARGSP);
int SASendACK (XMARGSP);
int SASEAlink (XMARGSP);
int SAIncBlk (XMARGSP);
typedef struct
{
char *state_name;
int (*state_func) (XMARGSP);
} ASTATES, *ASTATEP;
ASTATES ACK_States[] =
{
{"SAInit", SAInit},
{"SAEnd", SAEnd},
{"SA0", SAClearLine},
{"SA1", SASendACK},
{"SA2", SASEAlink},
{"SA3", SAIncBlk}
};
int
SAInit (XMARGSP args)
{
return ((int) args->control);
}
int
SAEnd (XMARGSP args)
{
return ((int) args->control);
}
int
SAClearLine (XMARGSP args)
{
long SA0Timer;
SA0Timer = timerset (3000);
if (args->options.SLO)
return (SA3);
if (args->options.SEAlink)
return (SA1);
while (CARRIER && !timeup (SA0Timer))
{
if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
time_release ();
continue;
}
return (SA1);
}
return (TIME_ERR);
}
int
SASendACK (XMARGSP args)
{
SENDBYTE (ACK);
args->sent_ACK = 1;
return (SA2);
}
int
SASEAlink (XMARGSP args)
{
if (!(args->options.SEAlink))
return (SA3);
SENDBYTE (args->blocknum);
SENDBYTE ((unsigned char) ~(args->blocknum));
return (SA3);
}
void
show_block (long b, char *c, XMARGSP args)
{
char j[100];
long k;
if (fullscreen && un_attended)
{
elapse_time ();
sb_move (filewin, 2, 2);
sb_puts (filewin, ultoa (((unsigned long) b), e_input, 10));
if (c)
sb_puts (filewin, c);
k = args->filelen - args->curr_byte;
if (k < 0L)
k = 0L;
(void) sprintf (j, "%3ld min",
((k * 10L / cur_baud.rate_value * 100L /
((args->save_header == SOH) ? 94L : 70L) + 59L) / 60L));
sb_move (filewin, 2, 69);
sb_puts (filewin, j);
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
(void) printf ("%s", ultoa (((unsigned long) b), e_input, 10));
if (c)
(void) printf ("%s", c);
}
}
int
SAIncBlk (XMARGSP args)
{
++(args->blocknum);
if ((args->options.SLO) &&
(((args->WriteBLK > 0) && (!((args->WriteBLK - 1) & 0x001F)) && (args->WriteBLK < args->total_blocks)) ||
(args->WriteBLK >= args->total_blocks)))
{
show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
}
else if ((!(args->options.SLO)) && (args->WriteBLK > 0))
{
show_block ((long) (args->WriteBLK - 1), NULL, args);
}
return (SUCCESS);
}
void
Send_ACK (XMARGSP args)
{
(void) state_machine ((STATEP) ACK_States, args, SA0);
}
void Send_Resync_Packet (XMARGSP);
int SNInit (XMARGSP);
int SNEnd (XMARGSP);
int SNClearLine (XMARGSP);
int SNSendNAK (XMARGSP);
int SNSEAlink (XMARGSP);
int SNAckResync (XMARGSP);
typedef struct
{
char *state_name;
int (*state_func) (XMARGSP);
} NSTATES, *NSTATEP;
NSTATES NAK_States[] =
{
{"SNInit", SNInit},
{"SNEnd", SNEnd},
{"SN0", SNClearLine},
{"SN1", SNSendNAK},
{"SN2", SNSEAlink},
{"SN3", SNAckResync}
};
int
SNInit (XMARGSP args)
{
return ((int) args->control);
}
int
SNEnd (XMARGSP args)
{
return ((int) args->control);
}
int
SNClearLine (XMARGSP args)
{
long SN0Timer;
SN0Timer = timerset (3000);
if (args->options.Resync)
{
Send_Resync_Packet (args);
return (SN3);
}
if (args->options.SEAlink)
return (SN1);
while (CARRIER && !timeup (SN0Timer))
{
if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
time_release ();
continue;
}
return (SN1);
}
return (TIME_ERR);
}
int
SNSendNAK (XMARGSP args)
{
if (args->options.do_CRC && (args->sent_ACK == 0))
SENDBYTE (WANTCRC);
else
SENDBYTE (NAK);
return (SN2);
}
int
SNSEAlink (XMARGSP args)
{
if (!(args->options.SEAlink))
return (SUCCESS);
SENDBYTE (args->blocknum);
SENDBYTE ((unsigned char) ~(args->blocknum));
return (SUCCESS);
}
int
SNAckResync (XMARGSP args)
{
long SN3Timer;
int c;
SN3Timer = timerset (3000);
while (CARRIER && !timeup (SN3Timer))
{
if ((unsigned int) (c = TIMED_READ (10)) == 0xffff)
{
Send_Resync_Packet (args);
continue;
}
if (c == ACK)
{
big_pause (1);
c = PEEKBYTE ();
if ((c == SOH) || (c == EOT))
return (SUCCESS);
}
}
if (!CARRIER)
return (CARRIER_ERR);
else
return (TIME_ERR);
}
void
Send_NAK (XMARGSP args)
{
(void) state_machine ((STATEP) NAK_States, args, SN0);
}
void
Send_Resync_Packet (XMARGSP args)
{
unsigned char resyncit[30];
unsigned short nak_crc;
SENDBYTE (SYN);
(void) sprintf ((char *) resyncit, "%ld", args->WriteBLK);
SENDCHARS ((char *) resyncit, strlen ((char *) resyncit), 1);
nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit));
SENDBYTE (ETX);
SENDBYTE ((unsigned char) (nak_crc & 0xff));
CLEAR_INBOUND ();
SENDBYTE ((unsigned char) (nak_crc >> 8));
}
void
Xmodem_Error (char *s, long block_number)
{
char j[50];
char k[50];
(void) sprintf (j, "%s %s %ld", s, MSG_TXT (M_ON_BLOCK), block_number);
(void) sprintf (k, "%-49.49s", j);
status_line (">Xmodem Error: %s", k);
if (fullscreen && un_attended)
{
sb_move (filewin, 2, 20);
sb_puts (filewin, k);
sb_show ();
}
else
{
gotoxy (locate_x + 20, locate_y);
(void) cputs (k);
}
}
void
Find_Char (int c)
{
long t1;
long t2;
t1 = timerset (3000);
t2 = timerset (100);
while (!timeup (t1) && !timeup (t2))
{
if (!CARRIER)
break;
if (PEEKBYTE () == (c & 0xff))
break;
else if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
t2 = timerset (100);
}
}
}
int
Header_in_data (unsigned char *p)
{
int i;
int j;
char *p1;
p1 = (char *) p;
++p1;
j = sizeof (XMDATA) - 2;
for (i = 1; i < j; i++, p1++)
{
if (*p1 == SOH)
{
(void) memcpy (p, p1, (unsigned int) (j - i));
return (j - i);
}
}
return (0);
}